import {
  h,
  FunctionalComponent,
  defineComponent,
  VNode,
  EmitsOptions,
  SetupContext
} from "vue";
import { useInjectHooks } from "@/composables/useInjectHooks";

type Component = ReturnType<typeof defineComponent>;

// eslint-disable-next-line @typescript-eslint/ban-types
const renderWrap = <P = {}, E extends EmitsOptions = {}>(
  wrappers: Component[],
  props: P,
  ctx: Omit<SetupContext<E>, "expose">,
  index = 0
): VNode => {
  return h(
    wrappers[index],
    {
      originalProps: props
    },
    index === wrappers.length - 1
      ? ctx.slots
      : () => renderWrap(wrappers, props, ctx, index + 1)
  );
};
const render: FunctionalComponent<{
  name: string;
}> = (_props, ctx) => {
  const hooks = useInjectHooks(_props.name);
  let base = ctx.slots.default?.() || [];
  const props = base[0]?.props || {};
  if (!hooks) return base;
  if (hooks.replace) {
    base = [h(hooks.replace, props, ctx.slots)];
  }
  if (hooks.wrap.length > 0) {
    base = [renderWrap(hooks.wrap, props, ctx)];
  }
  hooks.head
    .slice()
    .reverse()
    .forEach(component => {
      base.unshift(
        h(
          component,
          {
            originalProps: props
          },
          ctx.slots
        )
      );
    });
  hooks.tail.forEach(component => {
    base.push(
      h(
        component,
        {
          originalProps: props
        },
        ctx.slots
      )
    );
  });
  return base;
};

export default render;
